﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace CoolCode.Reflection
{
    //Last modified Sep 20, 2009*/
    public class BLReflection
    {
        public static System.Data.DataTable Convert(Type t)
        {
            System.Data.DataTable dt = new System.Data.DataTable();
            var ps = GetProperties(t);
            foreach (PropertyInfo p in ps)
                dt.Columns.Add(p.Name, p.PropertyType);
            return dt;
        }

        public static List<PropertyInfo> GetProperties(Type t)
        {
            PropertyInfo[] ps = t.GetProperties();
            return ps.ToList();
        }

        public static IEnumerable<object> GetPropValues(object obj)
        {
            Type t = obj.GetType();
            var ps = GetProperties(t);
            var result = from p in ps select p.GetValue(obj, null);
            return result;
        }

        //Add in Feb 07, 2009
        public static object GetPropValue(object obj, string propName)
        {
            Type t = obj.GetType();
            var p = t.GetProperty(propName);
            var result = p.GetValue(obj, null);
            return result;
        }

        public static object[] GetPropAttributes(object obj, string propName)
        {
            Type t = obj.GetType();
            var p = t.GetProperty(propName);
            var attr = p.GetCustomAttributes(true);
            return attr;
        }

        public static T[] GetPropAttribute<T>(object obj, string propName)
        {
            Type t = obj.GetType();
            var p = t.GetProperty(propName);
            Type attrType = typeof(T);
            var attr = p.GetCustomAttributes(attrType, true) as T[];
            return attr;
        }

        public static string[] GetPropFrom<A>(Type t, Func<A, bool> filter) where A : Attribute
        {
            var ps = GetProperties(t);
            Type attrType = typeof(A);
            List<string> result = new List<string>();
            foreach (var p in ps)
            {
                var attr = p.GetCustomAttributes(attrType, true) as A[];
                if (attr == null) return null;
                var filterResult = attr.Where(filter);
                if (filterResult.Count() != 0)
                {
                    result.Add(p.Name);
                }
            }
            return result.ToArray();
        }

        public static string[] GetPropFrom<A, C>(Func<A, bool> filter) where A : Attribute
        {
            Type t = typeof(C);
            return GetPropFrom<A>(t, filter);
        }

        public static IDictionary<string, object> ToDictionary<T>(T t) //where T : class
        {
            Type type = t.GetType();
            PropertyInfo[] ps = type.GetProperties();
            IDictionary<string, object> result = new Dictionary<string, object>(ps.Length);
            foreach (var p in ps)
                result.Add(p.Name, p.GetValue(t, null));
            return result;
        }

        public static string GetClassName<T>() //where T : class
        {
            var className = typeof(T).Name;
            return className;
        }

        public static T Parse<T>(string str) where T : struct
        {
            var type = typeof(T);
            var result = Parse(type, str);
            return (T)result;
        }

        /*Last modified Feb 21, 2009*/
        /// <summary>
        /// Invoke static method "Parse" from type
        /// </summary>
        /// <param name="type">the type which exist static method parse</param>
        /// <param name="str">param</param>
        /// <returns></returns>
        public static object Parse(Type type, string str)
        {
            object result;
            if (type.IsValueType)
            {
                switch (type.FullName)
                {
                    case "System.Guid":
                        result = Activator.CreateInstance(type, str);
                        break;
                    default:
                        var m = MFactory.GetParseMethod(type);
                        result = m.Invoke(null, new object[] { str });
                        break;
                }
            }
            else
            {
                switch (type.FullName)
                {
                    case "System.Guid":
                        result = Activator.CreateInstance(type, str);
                        break;
                    default:
                        return null;
                }
            }
            return result;
        }

        /// <summary>
        /// 显式转换
        /// </summary>
        public static T Cast<T>(object obj)
        {
            return (T)obj;
        }

        /// <summary>
        /// 显式转换
        /// </summary>
        /// <example>Cast(obj, 0);</example>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="type">占位</param>
        /// <returns></returns>
        public static T Cast<T>(object obj, T type)
        {
            return (T)obj;
        }
    }

    public static class MFactory
    {
        private static Dictionary<Type, MethodBase> _methods = null;
        public static Dictionary<Type, MethodBase> Methods
        {
            get
            {
                if (_methods == null)
                    _methods = new Dictionary<Type, MethodBase>();
                return _methods;
            }
        }

        /*Last modify Feb 21, 2009*/
        /*modify returen type MethodInfo to MethodBase*/
        public static MethodBase GetParseMethod(Type type)
        {
            if (!Methods.ContainsKey(type))
            {
                MethodBase m;
                switch (type.FullName)
                {
                    case "System.Guid":
                        m = type.GetConstructor(new Type[] { typeof(String) });
                        break;
                    default:
                        m = type.GetMethod("Parse", new Type[] { typeof(String) });
                        break;
                }
                Methods.Add(type, m);
            }
            return Methods[type];
        }
    }
}
